home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
LAPB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-12
|
20KB
|
535 lines
/* Link Access Procedures Balanced (LAPB) - with changes for rational
* behavior over packet radio
*/
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "ax25.h"
#include "lapb.h"
/* Process incoming frames */
int
lapb_input(axp,cmdrsp,bp)
register struct ax25_cb *axp; /* Link control structure */
char cmdrsp; /* Command/response flag */
struct mbuf *bp; /* Rest of frame, starting with ctl */
{
char control,p_control;
char frej = 0; /* FRMR reject reason code */
char class; /* General class (I/S/U) of frame */
int16 type,p_type; /* Specific type (I/RR/RNR/etc) of frame */
char pf; /* extracted poll/final bit */
char vr; /* extracted V(R) for I-frame */
char polled = 0;
char csum; /* checksum for sammler */
int16 ftype();
if(bp == NULLBUF || axp == NULLAX25){
free_p(bp);
return -1;
}
p_control = axp->control;
axp->control = control = pullchar(&bp);
type = ftype(control);
class = type & 0x3;
pf = control & PF;
/* Check for polls */
if(cmdrsp == COMMAND && pf)
polled = YES;
/* While we're disconnected, ignore all except SABM and DISC */
if(axp->state == DISCONNECTED && type != SABM && type != DISC){
if(polled)
axp->response = DM;
goto done;
}
/* Process implicit acknowledgements in all but U-frames */
if(class != U && ackours(axp,(control >> 5) & MMASK) == -1)
frej = Z; /* Out of range sequence number */
if(type != I && type != FRMR && len_mbuf(bp) != 0)
frej |= X|W; /* I-field not allowed */
/* Process final bit if a poll was outstanding */
if(axp->waitack && class != U && pf && cmdrsp == RESPONSE){
axp->waitack = NO;
axp->retries = 0;
stop_timer(&axp->t1);
/* Pick up retransmission at proper point */
axp->vs = (axp->vs - axp->unack) & MMASK;
axp->unack = 0;
axp->control = REJ; /* dirty: lapb_output sends single frame */
}
/* Resend FRMR for all except certain U while in error state */
if(axp->state == FRAMEREJECT && class != U){
goto done;
}
switch(type){
case SABM: /* Initialize or reset link */
switch(axp->state){
case DISCONNECTED:
lapbstate(axp,CONNECTED,LAPBCONN);
/* state-change upcall can force a DM by setting the
state to DISCONNECTED */
axp->response = (axp->state == CONNECTED)? UA : DM;
break;
case FRAMEREJECT:
lapbstate(axp,CONNECTED,LAPBRESF);
axp->response = UA;
break;
case CONNECTED:
lapbstate(axp,CONNECTED,LAPBNOMS);
axp->response = UA;
break;
case DISCPENDING:
axp->response = DM;
break;
case SETUP:
axp->response = UA;
break;
}
break;
case UA:
axp->retries = 0;
switch(axp->state){
case CONNECTED:
/* ignore an UA just after SABM or UA */
if ((p_type = ftype(p_control)) != UA &&
p_type != SABM){
lapbstate(axp,SETUP,LAPBNOMS);
sendctl(axp,COMMAND,SABM|PF);
}
break;
case SETUP:
stop_timer(&axp->t1);
lapbstate(axp,CONNECTED,LAPBCONN);
break;
case DISCPENDING:
lapbstate(axp,DISCONNECTED,LAPBDISC);
break;
/* note - ignored if DISCONNECTED or in FRAMEREJECT state */
}
break;
case DISC:
switch(axp->state){
case SETUP:
lapbstate(axp,DISCONNECTED,LAPBDISC);
axp->response = DM;
break;
case DISCPENDING:
axp->response = UA;
break;
default:
lapbstate(axp,DISCONNECTED,LAPBDISC);
axp->response = UA;
break;
}
break;
case RR:
axp->remotebusy = NO;
break;
case RNR:
axp->remotebusy = YES;
axp->retries = 0;
start_timer(&axp->t1); /* Probe as long as necessary */
break;
case REJ:
/* Crank back V(s) to start of queue */
axp->vs = (axp->vs - axp->unack) & MMASK;
axp->unack = 0;
break;
case I:
if (axp->state != CONNECTED){ /* apparently missed UA */
if (!run_timer(&axp->t1)) /* make sure timer is running */
start_timer(&axp->t1);
break; /* ignore the I-frame */
}
if(len_mbuf(axp->rxq) >= axp->window){
/* Too bad he didn't listen to us; he'll
* have to resend the frame later. This
* drastic action is necessary to avoid
* deadlock.
*/
axp->response = RNR;
break;
}
/* Extract V(R) and throw away the framesammler contents */
/* (A received frame always overrides the framesammler) */
free_p(axp->sammlq[vr = (control>>1) & MMASK]);
axp->sammlq[vr] = NULLBUF;
/* calculate a simple checksum over the frame. this is used */
/* to discard retransmissions of the same frame when using */
/* the framesammler. safety-first is the approach here. */
if (axp->maxsamml != 0 && bp != NULLBUF){
register struct mbuf *cbp;
register char *cdata;
register int ccnt;
csum = 0;
cbp = bp;
do {
cdata = cbp->data;
ccnt = cbp->cnt;
do {
csum += *cdata++;
} while (--ccnt);
} while ((cbp = cbp->next) != NULLBUF);
}
/* Reject or ignore I-frames with receive sequence number errors */
if(vr != axp->vr){
/* Check if we can store it in the framesammler */
/* we won't store frames with checksum equal to */
/* an equal-numbered (earlier) frame */
if(axp->t2.start != 0 && csum != axp->sammlchk[vr] &&
((vr - axp->vr) & MMASK) <= axp->maxsamml){
axp->sammlq[vr] = bp;
bp = NULLBUF;
}
if(axp->proto == V1 || !axp->rejsent){
axp->rejsent = YES;
axp->response = REJ;
}